/**
 * 
 */
package com.module.bp.ui;

import java.awt.Color;

import com.dalonedrau.jogl.engine.GameApplet;
import com.dalonedrau.jogl.engine.ProjectConstants;
import com.dalonedrau.jogl.opengl.sprite.BasicSpriteObject;
import com.dalonedrau.jogl.opengl.sprite.SpriteBase;
import com.dalonedrau.jogl.opengl.sprite.SpriteImageObject;
import com.dalonedrau.jogl.opengl.sprite.SpriteImageObjectFactory;
import com.dalonedrau.jogl.opengl.ui.Label;
import com.dalonedrau.jogl.opengl.ui.border.EmptyBorder;
import com.dalonedrau.jogl.opengl.ui.border.VXBorder;
import com.dalonedrau.jogl.opengl.ui.panel.CardPanel;
import com.dalonedrau.jogl.opengl.ui.panel.LandscapePagePanel;
import com.dalonedrau.jogl.opengl.ui.panel.Panel;
import com.dalonedrau.jogl.opengl.ui.panel.PortraitPagePanel;
import com.dalonedrau.pool.PooledStringBuilder;
import com.dalonedrau.pool.StringBuilderPool;
import com.dalonedrau.watchable.Watchable;
import com.dalonedrau.watchable.Watcher;
import com.module.bp.bus.BPHexMap;
import com.module.bp.engine.Turn;
import com.module.bp.player.BPCharacter;
import com.module.bp.player.BPParty;

/**
 * @author Donald
 */
public class PartyViewer extends PortraitPagePanel implements Watcher {
	/** the singleton instance of {@link PartyViewer}. */
	private static PartyViewer	instance;
	/**
	 * Gets the singleton instance of {@link PartyViewer}.
	 * @return {@link PartyViewer}
	 */
	public static PartyViewer getInstance() {
		if (PartyViewer.instance == null) {
			PartyViewer.instance = new PartyViewer();
		}
		return PartyViewer.instance;
	}
	private CardPanel		card;
	/** the panel for displaying gold and payroll. */
	private Panel pnlPay;
	/** the panel for displaying weight carried. */
	private Panel pnlWeight;
	/** the panel for displaying mounts. */
	private Panel pnlMounts;
	/** the panel for displaying food and food obligations. */
	private Panel pnlFood;
	private Label			lblDay;
	/** the label displaying the party's total landed mounts. */
	private Label			lblMount;
	/** the label displaying the party's total winged mounts. */
	private Label			lblWingedMount;
	/** the label displaying the party's total feedroll. */
	private Label			lblFeedroll;
	/** the label displaying the total weight the party is allowed to carry. */
	private Label			lblWeightAllowed;
	/** the label displaying the total weight the party is carrying. */
	private Label			lblWeightCarrying;	
	/** the label displaying the party's total food. */
	private Label			lblFood;
	/** the label displaying the party's total gold. */
	private Label			lblGold;
	private Label			lblHour;
	private Label			lblLocation;
	/** the label displaying the party's total payroll. */
	private Label			lblPayroll;
	/** the list of player viewers. */
	private PlayerViewer[]	vwrs	= new PlayerViewer[10];
	/**
	 * Creates a new instance of {@link PartyViewer}.
	 */
	private PartyViewer() {
		super(Panel.PORTRAIT_LEFT);
		super.setBorder(new VXBorder());
		// add arrow buttons

		// create viewers
		for (int i = 0; i < vwrs.length; i++) {
			vwrs[i] = new PlayerViewer();
		}
		// add card panel
		card = new CardPanel();
		PortraitPagePanel p0 = new PortraitPagePanel(Panel.PORTRAIT_CENTER);
		for (int i = 0; i < 5; i++) {
			p0.addChild(vwrs[i]);
		}
		card.addChild("0", p0);
		super.addChild(card);
		card.displayChild("0");
		card.setBorder(new EmptyBorder(0, 0, 8, 0));
		try {
			pnlPay = initGoldPanel();
			super.addChild(pnlPay);
			pnlFood = initFoodPanel();
			super.addChild(pnlFood);
			pnlMounts = initMountPanel();
			super.addChild(pnlMounts);
			pnlWeight = initWeightPanel();
			super.addChild(pnlWeight);
			super.addChild(initTimePanel());
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
		BPParty.getInstance().addWatcher(this);
		Turn.getInstance().addWatcher(this);
		try {
			update();
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
	}
	/**
	 * Gets the panel displaying the party's food.
	 * @return {@link Panel}
	 * @throws Exception if an error occurs
	 */
	private Panel initFoodPanel() throws Exception {
		Panel pnl = new LandscapePagePanel(Panel.LANDSCAPE_CENTER);
		SpriteBase sb = new BasicSpriteObject();
		SpriteImageObject img =
				SpriteImageObjectFactory.getInstance().getImageByName(
						"symbol_food");
		sb.setImageRefId(img.getRefId());
		sb.setWidth(img.getWidth());
		sb.setHeight(img.getHeight());
		Label lblIcon = new Label(sb);
		lblIcon.setBorder(new EmptyBorder(0, 0, 0, 4));
		pnl.addChild(lblIcon);
		lblFood =
				new Label(ProjectConstants.getInstance().getFontH1(), "  0");
		pnl.addChild(lblFood);
		pnl.addChild(
				new Label(ProjectConstants.getInstance().getFontH1(), "/"));
		lblFeedroll =
				new Label(ProjectConstants.getInstance().getFontH1(), "0");
		pnl.addChild(lblFeedroll);
		pnl.setTooltipText("");
		return pnl;
	}
	/**
	 * Gets the panel displaying the party's weight.
	 * @return {@link Panel}
	 * @throws Exception if an error occurs
	 */
	private Panel initWeightPanel() throws Exception {
		Panel pnl = new LandscapePagePanel(Panel.LANDSCAPE_CENTER);
		SpriteBase sb = new BasicSpriteObject();
		SpriteImageObject img =
				SpriteImageObjectFactory.getInstance().getImageByName(
						"symbol_scales");
		sb.setImageRefId(img.getRefId());
		sb.setWidth(img.getWidth());
		sb.setHeight(img.getHeight());
		Label lblIcon = new Label(sb);
		lblIcon.setBorder(new EmptyBorder(0, 0, 0, 4));
		pnl.addChild(lblIcon);
		lblWeightCarrying =
				new Label(ProjectConstants.getInstance().getFontH1(), "  0");
		pnl.addChild(lblWeightCarrying);
		pnl.addChild(
				new Label(ProjectConstants.getInstance().getFontH1(), "/"));
		lblWeightAllowed =
				new Label(ProjectConstants.getInstance().getFontH1(), "0");
		pnl.addChild(lblWeightAllowed);
		pnl.setTooltipText("");
		return pnl;
	}
	/**
	 * Gets the panel displaying the party's food.
	 * @return {@link Panel}
	 * @throws Exception if an error occurs
	 */
	private Panel initMountPanel() throws Exception {
		Panel pnl = new LandscapePagePanel(Panel.LANDSCAPE_CENTER);
		SpriteBase sb = new BasicSpriteObject();
		SpriteImageObject img =
				SpriteImageObjectFactory.getInstance().getImageByName(
						"symbol_mount");
		sb.setImageRefId(img.getRefId());
		sb.setWidth(img.getWidth());
		sb.setHeight(img.getHeight());
		Label lblIcon = new Label(sb);
		lblIcon.setBorder(new EmptyBorder(0, 0, 0, 4));
		pnl.addChild(lblIcon);
		lblMount =
				new Label(ProjectConstants.getInstance().getFontH1(), "  0");
		pnl.addChild(lblMount);
		pnl.addChild(
				new Label(ProjectConstants.getInstance().getFontH1(), "/"));
		lblWingedMount =
				new Label(ProjectConstants.getInstance().getFontH1(), "0");
		pnl.addChild(lblWingedMount);
		pnl.setTooltipText("");
		return pnl;
	}
	/**
	 * Gets the panel displaying the party's gold.
	 * @return {@link Panel}
	 * @throws Exception if an error occurs
	 */
	private Panel initGoldPanel() throws Exception {
		Panel pnl = new LandscapePagePanel(Panel.LANDSCAPE_CENTER);
		SpriteBase sb = new BasicSpriteObject();
		SpriteImageObject img =
				SpriteImageObjectFactory.getInstance().getImageByName(
						"symbol_gold");
		sb.setImageRefId(img.getRefId());
		sb.setWidth(img.getWidth());
		sb.setHeight(img.getHeight());
		Label lblIcon = new Label(sb);
		lblIcon.setBorder(new EmptyBorder(0, 0, 0, 4));
		pnl.addChild(lblIcon);
		lblGold =
				new Label(ProjectConstants.getInstance().getFontH1(), "  0");
		pnl.addChild(lblGold);
		pnl.addChild(
				new Label(ProjectConstants.getInstance().getFontH1(), "/"));
		lblPayroll =
				new Label(ProjectConstants.getInstance().getFontH1(), "0");
		pnl.addChild(lblPayroll);
		return pnl;
	}
	/**
	 * Gets the panel displaying the game time.
	 * @return {@link Panel}
	 * @throws Exception if an error occurs
	 */
	private Panel initTimePanel() throws Exception {
		Panel pnl = new PortraitPagePanel(Panel.PORTRAIT_LEFT);
		lblDay =
				new Label(ProjectConstants.getInstance().getFontH2(), " ");
		pnl.addChild(lblDay);
		lblHour =
				new Label(ProjectConstants.getInstance().getFontH2(), " ");
		pnl.addChild(lblHour);
		lblLocation =
				new Label(ProjectConstants.getInstance().getFontH2(), " ");
		pnl.addChild(lblLocation);
		return pnl;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void prepareForRendering() throws Exception {
		// TODO Auto-generated method stub
		super.prepareForRendering();
	}
	public void update() throws Exception {
		// extend the length of the array if needed
		int len = BPParty.getInstance().getMembers().length;
		if (len > vwrs.length) {
			PlayerViewer[] dest =
					new PlayerViewer[BPParty.getInstance().getMembers().length];
			System.arraycopy(vwrs, 0, dest, 0, vwrs.length);
			vwrs = dest;
			dest = null;
		}
		for (int i = 0; i < len; i++) {
			BPCharacter pc = BPParty.getInstance().getMembers()[i];
			if (vwrs[i] == null) {
				vwrs[i] = new PlayerViewer();
			}
			vwrs[i].setPlayerId(pc.getRefId());
		}
		for (int i = len; i < vwrs.length; i++) {
			if (vwrs[i] != null) {
				vwrs[i].setPlayerId(-1);
			}
		}
		long g = BPParty.getInstance().getPartyGold();
		int p = BPParty.getInstance().getPartyPayroll();
		int f = BPParty.getInstance().getPartyFood();
		int o = BPParty.getInstance().getPartyFoodObligation();
		// set gold
		PooledStringBuilder sb =
				StringBuilderPool.getInstance().getStringBuilder();
		sb.append(g);
		lblGold.setText(sb.toString());
		sb.setLength(0);
		if (g < p) {
			lblGold.setColor(Color.RED);
			sb.append("You have ");
			sb.append(g);
			sb.append(" gold available, but you must have ");
			sb.append(p);
			sb.append(" gold to pay your followers by the ");
			sb.append("end of the day, or they will begin to abandon you.");
			this.pnlPay.setTooltipText(sb.toString());
		} else {
			lblGold.setColor(Color.WHITE);
			sb.append("You have ");
			sb.append(g);
			if (p > 0) {
				sb.append(" gold available, enough to pay ");
				sb.append("your warband for the day.");				
			} else {
				sb.append(" gold available.");
			}
			this.pnlPay.setTooltipText(sb.toString());
		}
		sb.setLength(0);
		// set payroll
		sb.append(p);
		lblPayroll.setText(sb.toString());
		sb.setLength(0);

		// set food
		sb.append(f);
		lblFood.setText(sb.toString());
		sb.setLength(0);
		if (f < o) {
			lblFood.setColor(Color.RED);
			sb.append("You have ");
			sb.append(f);
			sb.append(" food rations available, but you must have at least ");
			sb.append(o);
			sb.append(" food ");
			if (o == 1) {
				sb.append(" ration ");
			} else {
				sb.append(" rations ");
			}
			sb.append(" to feed your warband by the ");
			sb.append("end of the day, or you will begin to starve.");
			this.pnlFood.setTooltipText(sb.toString());
		} else {
			lblFood.setColor(Color.WHITE);
			sb.append("You have ");
			sb.append(f);
			sb.append(" food rations available, enough to feed ");
			sb.append("your warband for the day.");
			this.pnlFood.setTooltipText(sb.toString());
		}
		sb.setLength(0);
		// set foodroll
		sb.append(o);
		lblFeedroll.setText(sb.toString());
		sb.setLength(0);
		
		// set mounts
		sb.append(BPParty.getInstance().getNumberOfMounts());
		lblMount.setText(sb.toString());
		sb.setLength(0);
		sb.append(BPParty.getInstance().getNumberOfWingedMounts());
		lblWingedMount.setText(sb.toString());
		sb.setLength(0);
		if (BPParty.getInstance().getNumberOfMounts() 
				+ BPParty.getInstance().getNumberOfWingedMounts() == 0) {
			sb.append("You have no mounts, winged or otherwise.");
			this.pnlMounts.setTooltipText(sb.toString());
		} else {
			sb.append("You have ");
			sb.append(BPParty.getInstance().getNumberOfMounts());
			sb.append(" mounts and ");
			sb.append(BPParty.getInstance().getNumberOfWingedMounts());
			sb.append(" winged mounts.");
			this.pnlMounts.setTooltipText(sb.toString());
		}
		sb.setLength(0);

		// set transport capacity
		sb.append(BPParty.getInstance().getWeightCarried());
		this.lblWeightCarrying.setText(sb.toString());
		sb.setLength(0);
		if (BPParty.getInstance().getWeightCarried() 
				> BPParty.getInstance().getPartyCarryingLoad()) {
			lblWeightCarrying.setColor(Color.RED);
			sb.append("The warband is carrying more than it can transport! ");
			sb.append("You will need to cache some gold or treasure ");
			sb.append("in a secret location before you ");
			sb.append("can move on from this place.");
			this.pnlWeight.setTooltipText(sb.toString());
		} else {
			lblWeightCarrying.setColor(Color.WHITE);
			if (BPParty.getInstance().getNumberOfMounts() > 0
					|| BPParty.getInstance().getNumberOfWingedMounts() > 0) {
				// check to see if party can fly or ride
				if (BPParty.getInstance().canTravelFlying()
						|| BPParty.getInstance().canTravelMounted()) {
					if (BPParty.getInstance().canTravelFlying()) {
						sb.append("You are carrying ");
						sb.append(BPParty.getInstance().getWeightCarried());
						sb.append(" weight ");
						if (BPParty.getInstance().getWeightCarried() == 1) {
							sb.append(" load; ");					
						} else {
							sb.append(" loads; ");					
						}
						sb.append("your warband can carry up to a maximum of ");
						int w = BPParty.getInstance().getNumberOfWingedMounts();
						w *= 30;
						w -= BPParty.getInstance().getPartyRidingLoad();
						sb.append(w);
						sb.append(" loads and still fly your winged mounts.");
						pnlWeight.setTooltipText(sb.toString());
					} else {
						sb.append("You are carrying ");
						sb.append(BPParty.getInstance().getWeightCarried());
						sb.append(" weight ");
						if (BPParty.getInstance().getWeightCarried() == 1) {
							sb.append(" load; ");					
						} else {
							sb.append(" loads; ");					
						}
						sb.append("your warband can carry up to a maximum of ");
						int w = BPParty.getInstance().getNumberOfWingedMounts();
						w += BPParty.getInstance().getNumberOfMounts();
						w *= 30;
						w -= BPParty.getInstance().getPartyRidingLoad();
						sb.append(w);
						sb.append(" loads and still ride your mounts.");
						pnlWeight.setTooltipText(sb.toString());
					}
				} else {
					sb.append("You are carrying ");
					sb.append(BPParty.getInstance().getWeightCarried());
					sb.append(" weight ");
					if (BPParty.getInstance().getWeightCarried() == 1) {
						sb.append(" load, ");					
					} else {
						sb.append(" loads, ");					
					}
					sb.append("but cannot ride your mounts; ");
					sb.append("some of your warband will need to walk.");
					this.pnlWeight.setTooltipText(sb.toString());
					
				}
			} else {
				sb.append("You are carrying ");
				sb.append(BPParty.getInstance().getWeightCarried());
				sb.append(" weight ");
				if (BPParty.getInstance().getWeightCarried() == 1) {
					sb.append(" load; ");					
				} else {
					sb.append(" loads; ");					
				}
				sb.append("your warband can carry up to a maximum of ");
				sb.append(BPParty.getInstance().getPartyCarryingLoad());
				sb.append(" loads and still travel.");
				this.pnlWeight.setTooltipText(sb.toString());
			}
		}
		sb.setLength(0);
		// set weight capacity
		sb.append(BPParty.getInstance().getPartyCarryingLoad());
		lblWeightAllowed.setText(sb.toString());
		sb.setLength(0);

		// set time, location
		lblDay.setText(Turn.getInstance().getDayString());
		lblHour.setText(Turn.getInstance().getPhaseString());
		lblLocation.setText(
				BPHexMap.getInstance().getHexName(
						BPParty.getInstance().getCurrentHex()));

		sb.returnToPool();
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void watchUpdated(final Watchable data) {
		try {
			update();
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
	}
}
